import string
import os
import time
import types
import socket
import cPickle
import hashlib

import simplejson as json

from bsddb3 import db

"""
    Copyright (C) 2009,2010  Jorge Alegre Vilches

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
"""

TYPE_LIST = 'list'
TYPE_DICT = 'dict'
TYPE_TUPLE_LIST = 'tuple_list'

def _cleanList(TupleTmpList):
	return TupleTmpList

def _cleanList(TupleTmpList):
	TupleList = []
	for Tuple in TupleTmpList:
		if type(Tuple) == types.TupleType or type(Tuple) == types.ListType:
			sName, sValue = Tuple
			try:
				if sName == 'None':
					sName = None
				if sValue == 'None':
					sValue = None
				else:
					sName = str(sName)
					sValue = str(sValue)
			except UnicodeEncodeError:
				sName = sName.encode('utf-8')
				sValue = sValue.encode('utf-8')
			TupleNew = [sName, sValue]
			TupleList.append(TupleNew) 
		else:
			sName = Tuple
			if sName == 'None':
				sName = None
			else:
				try:
					sName = str(sName)
				except UnicodeEncodeError:
					# Should check encoding from data, then apply encoding
					sName = sName.encode('utf-8')
			TupleList.append(sName)
	return TupleList

class DbmException(Exception):
	sOp = ''
	sContainer = ''
	sValue = ''
	ArgsDict = {}
	ErrMsg = ''
	def __init__(self, sOp, sContainer, **ArgsDict):
		self.sOp = sOp
		self.sContainer = sContainer
		self.ArgsDict = ArgsDict
		errMsg = 'Octopus error in operation ' + str(self.sOp) + ' and table ' + str(self.sContainer)
		List = self.ArgsDict.keys()
		for sName in List:
			if sName != 'msg':
				if len(str(ArgsDict[sName])) < 15:
					errMsg = errMsg + ', ' + str(sName) + '=' + str(ArgsDict[sName])
				else:
					errMsg = errMsg + ', ' + str(sName) + '=' + '*****'
			else:
				if ArgsDict[sName]:
					errMsg = errMsg + '\r\n***** SERVER ERROR FOLLOWS *****\r\n' + str(ArgsDict[sName]) + ' '
		self.ErrMsg = errMsg
	def __str__(self):
		errMsg = self.ErrMsg
		return str(errMsg)

class DbmAuthException(Exception):
	iErrorCode = 0
	def __init__(self, iErrorCode):
		self.iErrorCode = iErrorCode
	def __str__(self):
		if self.iErrorCode == 100:
			errMsg = 'Dbmd password authorization error'
		elif self.iErrorCode == 110:
			errMsg = 'Dbmd format validation error'
		return str(errMsg)

class DbmConnect:
	__RequestDict = {}
	__EnvName = ''
	__EnvPath = ''
	__ConnectDict={'host':'', 'port':9346}
	__sHostName = ""
	__sUser = ''
	__sPassword = ''
	__iDbId = 0
	def __init__(self):
		pass
	def setHostName(self, sHostName):
		self.__ConnectDict['host'] = sHostName
		self.__sHostName = sHostName
	def getHostName(self):
		return self.__sHostName
	def getUser(self):
		return self.__sUser
	def setUser(self, sUser):
		self.__sUser = sUser
	def getPassword(self):
		return self.__sPassword
	def setPassword(self, sPassword):
		self.__sPassword = sPassword
	def getEnvName(self):
		return self.__EnvName
	def setEnvName(self, sEnvName):
		self.__EnvName = sEnvName
	def getEnvPath(self):
		return self.__EnvPath
	def setEnvPath(self, sEnvPath):
		self.__EnvPath = sEnvPath
	def getDbId(self):
		return self.__iDbId
	def setDbId(self, iDbId):
		self.__iDbId = iDbId
	def __toStrDict(self, DictTmp):
		Dict = {}
		for Key in DictTmp.keys():
			value = DictTmp[Key]
			if type(value) == types.UnicodeType:
				Dict[str(Key)] = str(DictTmp[Key])
			else:
				Dict[str(Key)] = DictTmp[Key]
		return Dict
	def __toStringDict(self, Dict):
		"""
		@param Dict: Dictionary with unicode keys
		@return: Dict: Dictionary with string keys
		"""
		List = Dict.keys()
		NewDict = {}
		for sKey in List:
			sValue = Dict[sKey]
			if type(sValue) == types.StringType or type(sValue) == types.UnicodeType:
				sValue = str(sValue)
			NewDict[str(sKey)] = sValue
		return NewDict
	def sendDataDb(self, RequestDict, bResponse=True, sMode='r'):
		sPid = os.getpid()
		RequestDict['sEnvName'] = self.__EnvName
		RequestDict['iDbId'] = self.__iDbId
		RequestDict['bResponse'] = bResponse
		RequestDict['sMode'] = sMode
		"""if RequestDict.has_key('sValue'):
			try:
				SValue = unicode(RequestDict['sValue'], 'utf-8')
			except UnicodeDecodeError:
				SValue = unicode(RequestDict['sValue'], 'latin1')
				RequestDict['sValue'] = SValue.encode('utf-8')"""
		#print 'RequestDict->', RequestDict
		#SRequestDict = json.dumps(RequestDict)
		#print 'JSON->', SRequestDict 
		sRequestDict = cPickle.dumps(RequestDict, 1)
		oHash = hashlib.sha512()
		oHash.update(self.__sPassword)
		sHexPassword = oHash.hexdigest()
		sUser = self.__sUser.ljust(100)
		sEnvName = self.__EnvName.ljust(100)
		firstLine = sUser + ';' + sHexPassword + ';' + sEnvName + '\r\n'
		sResponse = firstLine + sRequestDict
		"""TO DO: open() and Env.open() will create socket connections, open connection and keep open, so that the 0.0004 seconds
		needed to open a connection is not needed and improves performance. Changes in server are needed in order to keep connections
		alive."""
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		s.connect((self.getHostName(), self.__ConnectDict['port']))
		s.sendall(sResponse)
		if bResponse:
			reply = []
			while 1:
				try:
					data = s.recv(16384)
					if not data: break
					reply.append(data)
				except socket.error:
					a = 1
			s.close()
			response = string.join(reply,'')
			if response:
				#ResponseDict = self.__toStrDict(jsonpickle.decode(response))
				#ResponseDict = cPickle.loads(response)
				#ResponseDict = json.loads(response)
				#ResponseDict = self.__toStringDict(ResponseDict)
				ResponseDict = cPickle.loads(response)
			else:
				ResponseDict = {}
				ResponseDict['bResult'] = False
		else:
			s.close()
			ResponseDict = {}
		#print 'ResponseDict->', ResponseDict
		return ResponseDict

class DbEnv:
	_sEnvName = ''
	_EnvPath = ''
	_sDataDir = ''
	_sTmpDir = ''
	_sLogDir = ''
	_CacheSizeTuple = ()
	_RequestDict = {}
	_iDbId = -1
	_sUser = ''
	_sPassword = ''
	_sTableName = ''
	def __init__(self, sHostName='', sEnvName='', sUser='', sPassword=''):
		self.oDbmConnect = DbmConnect()
		self._sEnvName = sEnvName
		self.oDbmConnect.setEnvName(sEnvName)
		self._EnvName = sEnvName
		self._sTableName = sEnvName
		self._iDbId = -1
		self.oDbmConnect.setDbId(-1)
		self.oDbmConnect.setUser(sUser)
		self.oDbmConnect.setPassword(sPassword)
		self.oDbmConnect.setHostName(sHostName)
	def _sendDataDb(self, bResponse=True):
		ResponseDict = self.oDbmConnect.sendDataDb(self._RequestDict, bResponse)
		return ResponseDict
	def close(self):
		self._RequestDict['sOp'] = 'closeEnv'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('closeEnv()', self._sTableName)
	def closeAll(self):
		self._RequestDict['sOp'] = 'closeAllEnv'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('closeAllEnv()', self._sTableName)
	def getEnvName(self):
		return self._EnvName
	def getEnvPath(self):
		return self._EnvPath
	def reOpenAll(self):
		self._RequestDict['sOp'] = 'reOpenAll'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('reOpenAll()', self._sTableName)
	def getDataDict(self):
		self._RequestDict['sOp'] = 'getDataDict'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('getDataDict()', self._sTableName)
		else:
			DataDict = Dict['List'][0]
		return DataDict
	def lock(self):
		self._RequestDict['sOp'] = 'lock_server'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('lock()', self._sTableName)
	def unlock(self):
		self._RequestDict['sOp'] = 'unlock_server'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('unlock()', self._sTableName)
	def __str__(self):
		self.getEnvName()
	def open(self, sPath, iFlags):
		self._RequestDict['sOp'] = 'openEnv'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['iFlags'] = iFlags
		self._RequestDict['sDataDir'] = self._sDataDir
		self._RequestDict['sTmpDir'] = self._sTmpDir
		self._RequestDict['sLogDir'] = self._sLogDir
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			raise DbmException('openEnv()', self._sEnvName)
	def set_data_dir(self, sPath):
		self._sDataDir = sPath
	def set_tmp_dir(self, sPath):
		self._sTmpDir = sPath
	def set_lg_dir(self, sPath):
		self._sLogDir = sPath
	def set_cachesize(self, iCacheSizeBig, iCacheSize):
		self._CacheSizeTuple = (iCacheSizeBig, iCacheSize)

class Dbm:
	_RequestDict = {'iDbId': -1}
	_iDbId = -1
	_iCursor = -1
	_CacheSizeTuple = (0, 0)
	_sEnvName = ''
	_sTableName = ''
	_bDup = False
	_iFlagsAdd = 0
	_iSpoolSize = 0
	_DbmCursor = None
	_sMode = ''
	_sUser = ''
	_sPassword = ''
	_sHostName = ''
	_sMode = 'r'
	__TARGET_LOCAL = 'local'
	__TARGET_SPOOL = 'spool'
	__MODE_WRITE = 'w'
	__MODE_READ = 'r'
	__Socket = None
	__Port = 9346
	def __init__(self, sHostName, sUser, sPassword, oDbEnv=None):
		"""Note: oDbEnv can be either an DbEnv object or the environment name (string)."""
		self._RequestDict = {'iDbId': -1}
		self._iDbId = -1
		self.oDbmConnect = DbmConnect()
		self.oDbmConnect.setDbId(-1)
		self.oDbmConnect.setHostName(sHostName)
		self.oDbmConnect.setUser(sUser)
		self.oDbmConnect.setPassword(sPassword)
		self._sUser = sUser
		self._sPassword = sPassword
		self._sHostName = sHostName
		if oDbEnv:
			if type(oDbEnv) == types.StringType:
				self._sEnvName = oDbEnv
			else:
				self._sEnvName = oDbEnv.getEnvName()
			self.oDbmConnect.setEnvName(self._sEnvName)
		self._sMode = 'r'
		self._iCursor = -1
	def _resetDict(self):
		self._RequestDict = {'ParamDict': {}, 'iDbId': -1}
	def _sendDataDb(self, bResponse=True):
		ResponseDict = self.oDbmConnect.sendDataDb(self._RequestDict, bResponse, sMode=self._sMode)
		return ResponseDict
	def _cleanStrFields(self, sName):
		if type(sName) == types.UnicodeType:
			sNameFinal = sName.encode('utf-8')
		else:
			sNameFinal = sName
		return sNameFinal
	def _cleanList(self, TupleTmpList):
		TupleList = []
		for Tuple in TupleTmpList:
			if type(Tuple) == types.TupleType or type(Tuple) == types.ListType:
				sName, sValue = Tuple
				sName = str(sName)
				sValue = str(sValue)
				TupleNew = [sName, sValue]
				TupleList.append(TupleNew)
			else:
				sName = str(Tuple)
				TupleList.append(sName)
		return TupleList
	def _isModeOk(self):
		pass
	def open(self, sPath, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, sMode='r'):
		"""Open database file. Returns None. Examples:
		open('/index/test/test.db', db.DB_BTREE, db.DB_CREATE, sDbName='idx1.idx', iFileMode=0777)
		open('/index/test/test.db', db.DB_BTREE, db.DB_CREATE)
		open('/index/test/test.db', db.DB_CREATE)
		open('/index/test/test.db')
		"""
		self._sMode = sMode
		self._resetDict()
		self._RequestDict['sOp'] = 'open'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd 
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['iTxn'] = iTxn
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._sTableName = sPath
		Dict = self._sendDataDb()
		if Dict['bResult']:
			iDbId = Dict['List'][0]
			if iDbId:
				self._iDbId = iDbId
				self.oDbmConnect.setDbId(iDbId)
		elif Dict.has_key('iErrorCode'):
			raise DbmAuthException(Dict['iErrorCode'])
		else:
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			#print sErrMsg
			raise DbmException('open()', self._sTableName, msg=sErrMsg)
	def close(self):
		"""Close database file."""
		self._resetDict()
		self._RequestDict['sOp'] = 'close'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('close()', self._sTableName, msg=sErrMsg)
	def getId(self):
		return self._iDbId
	def has_key(self, sName):
		"""Checks that sName exists in table. Returns boolean."""
		self._resetDict()
		self._RequestDict['sOp'] = 'has_key'
		self._RequestDict['sName'] = self._cleanStrFields(sName)
		Dict = self._sendDataDb()
		if Dict['bResult']:
			bExists = Dict['List'][0]
			return bExists
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('has_key()', self._sTableName, sName=sName, msg=sErrMsg)
	def set_cachesize(self, iCacheSizeBig, iCacheSizeSmall):
		"""Defines the spool memory for table in bytes. iCacheSizeBig is in GB, iCacheSizeSmall in bytes 64000000 is 64MB. Returns None."""
		self._CacheSizeTuple = (iCacheSizeBig, iCacheSizeSmall)
	def set_flags(self, iFlagsAdd):
		"""Defines the flags used when opening table. Returns None."""
		self._iFlagsAdd = iFlagsAdd
	def put(self, sName, sValue):
		"""Puts sName, sValue pair in table. Returns None."""
		if self._sMode == 'r':
			raise DbmException('put()', self._sTableName, sName=sName, sValue=sValue, msg='No write privileges, must open with sMode="w".')
		else:
			self._resetDict()
			self._RequestDict['sOp'] = 'put'
			self._RequestDict['sName'] = self._cleanStrFields(sName)
			self._RequestDict['sValue'] = self._cleanStrFields(sValue)
			Dict = self._sendDataDb()
			if not Dict['bResult']:
				self.close()
				sErrMsg = ''
				if Dict.has_key('sError'):
					sErrMsg = Dict['sError']
				raise DbmException('put()', self._sTableName, sName=sName, sValue=sValue, msg=sErrMsg)
	def __getitem__(self, sName):
		sValue = self.get(sName)
		if sValue == None:
			raise KeyError
		return sValue
	def __setitem__(self, sName, sValue):
		self.put(sName, sValue)
	def __delitem__(self, sName):
		self.delete(sName)
	def putList(self, DataList):
		"""Puts DataList [(sName, sValue),(sName, sValue),...] in table. Returns None."""
		if self._sMode == 'r':
			raise DbmException('putList()', self._sTableName, msg='No write privileges, must open with sMode="w".')
		else:
			DataNewList = []
			for Tuple in DataList:
				sName, sValue = Tuple
				sName = self._cleanStrFields(sName)
				sValue = self._cleanStrFields(sValue)
				DataNewList.append((sName, sValue))
			self._resetDict()
			self._RequestDict['sOp'] = 'putList'
			self._RequestDict['DataList'] = DataNewList
			Dict = self._sendDataDb()
			if not Dict['bResult']:
				self.close()
				sErrMsg = ''
				if Dict.has_key('sError'):
					sErrMsg = Dict['sError']
				raise DbmException('putList()', self._sTableName, msg=sErrMsg)
	def get(self, sName):
		"""Get key sName. Returns sValue."""
		self._resetDict()
		self._RequestDict['sOp'] = 'get'
		self._RequestDict['sName'] = self._cleanStrFields(sName)
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#sValue = _cleanList(Dict['List'])[0]
			sValue = Dict['List'][0]
			return sValue
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('get()', self._sTableName, sName=sName, msg=sErrMsg)
	def getList(self, NameList, sType=TYPE_TUPLE_LIST):
		"""Get list of keys for NameList. Returns TupleList."""
		NameNewList = []
		for sName in NameList:
			sNameNew = self._cleanStrFields(sName)
			NameNewList.append(sNameNew)
		self._resetDict()
		self._RequestDict['sOp'] = 'getList'
		self._RequestDict['NameList'] = NameNewList
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
			if sType == TYPE_LIST:
				Result = TupleList
				Result = []
				for Tuple in TupleList:
					Result.append(Tuple[1])
			elif sType == TYPE_TUPLE_LIST:
				Result = TupleList
			else:
				ResultDict = {}
				for Tuple in TupleList:
					name, value = Tuple						
					ResultDict[name] = value
				Result = ResultDict
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('getList()', self._sTableName, msg=sErrMsg)
		return Result
	def check(self, sName):
		"""Checks for sName. Returns boolean."""
		bKey = self.has_key(sName)
		return bKey
	def checkList(self, NameList):
		"""Checks for a list of keys. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'checkList'
		self._RequestDict['NameList'] = NameList
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
			return TupleList
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('checkList()', self._sTableName, msg=sErrMsg)
	def keys(self):
		"""Get list of keys. Returns a list of key names. Returns NameList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'keys'
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#NameList = _cleanList(Dict['List'])
			NameList = Dict['List']
			return NameList
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('keys()', self._sTableName, msg=sErrMsg)
	def items(self):
		"""Get list of key pairs. Returns ItemList, a list of tuples."""
		self._resetDict()
		self._RequestDict['sOp'] = 'items'
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#ItemList = _cleanList(Dict['List'])
			ItemList = Dict['List']
			return ItemList
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('items()', self._sTableName, msg=sErrMsg)
	def values(self):
		"""Get list of key values. Returns ValueList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'values'
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#ValueList = _cleanList(Dict['List'])
			ValueList = Dict['List']
			return ValueList
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('values()', self._sTableName, msg=sErrMsg)
	def delete(self, sName):
		"""Deletes a key. Returns None."""
		if self._sMode == 'r':
			raise DbmException('delete()', self._sTableName, sName=sName, msg='No write privileges, must open with sMode="w".')
		else:
			self._resetDict()
			self._RequestDict['sOp'] = 'delete'
			self._RequestDict['sName'] = self._cleanStrFields(sName)
			Dict = self._sendDataDb()
			if not Dict['bResult']:
				self.close()
				sErrMsg = ''
				if Dict.has_key('sError'):
					sErrMsg = Dict['sError']
				raise DbmException('delete()', self._sTableName, sName=sName, msg=sErrMsg)
	def cursor(self):
		"""Creates a cursor. Returns a DbmCursor instance."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self.close()
			sErrMsg = Dict['sError']
			raise DbmException('cursor()', self._sTableName, msg=sErrMsg)
		else:
			self._iCursor = Dict['List'][0]
			self._DbmCursor = DbmCursor(self, self._iDbId, self._iCursor, self._sHostName, self._sTableName, self._sUser, self._sPassword, sMode=self._sMode)
		return self._DbmCursor
	def sync(self):
		"""Sync data from spool to disk. Returns None."""
		self._resetDict()
		self._RequestDict['sOp'] = 'sync'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('sync()', self._sTableName, msg=sErrMsg)
	def truncate(self):
		"""Deletes all keys from table. Returns None."""
		self._resetDict()
		self._RequestDict['sOp'] = 'truncate'
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('truncate()', self._sTableName, msg=sErrMsg)
	def getDirect(self, sPath, sName, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None):
		"""Get key value. No need to open database file first. Returns sValue."""
		self._resetDict()
		self._RequestDict['sOp'] = 'getDirect'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['sName'] = self._cleanStrFields(sName)
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iTxn'] = iTxn
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#sValue = _cleanList(Dict['List'])[0]
			sValue = Dict['List'][0]
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('getDirect()', sPath, sName=sName, msg=sErrMsg)
		return sValue
	def getListDirect(self, sPath, NameList, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, sType=TYPE_TUPLE_LIST):
		"""Gets list of key values. No need to open database file first. Returns ValueList."""
		NameNewList = []
		for sName in NameList:
			sNameNew = self._cleanStrFields(sName)
			NameNewList.append(sNameNew)
		self._resetDict()
		self._RequestDict['sOp'] = 'getListDirect'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['NameList'] = NameNewList
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iTxn'] = iTxn		
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#ValueList = _cleanList(Dict['List'])
			ValueList = Dict['List']
			if sType == TYPE_LIST:
				Result = []
				for Tuple in ValueList:
					Result.append(Tuple[1])
			elif sType == TYPE_TUPLE_LIST:
				Result = ValueList
			else:
				ResultDict = {}
				for Tuple in ValueList:
					name, value = Tuple
					ResultDict[name] = value
				Result = ResultDict
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('getListDirect()', sPath, msg=sErrMsg)
		return Result
	def putDirect(self, sPath, sName, sValue, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, bResponse=True):
		"""Puts a key into database file. No need to open file first. Returns None."""
		self._resetDict()
		self._sMode = 'w'
		self._RequestDict['sOp'] = 'putDirect'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['iTxn'] = iTxn
		self._RequestDict['sName'] = self._cleanStrFields(sName)
		self._RequestDict['sValue'] = self._cleanStrFields(sValue)
		Dict = self._sendDataDb(bResponse=bResponse)
		if bResponse:
			if not Dict['bResult']:
				self.close()
				sErrMsg = ''
				if Dict.has_key('sError'):
					sErrMsg = Dict['sError']
				raise DbmException('putDirect()', sPath, msg=sErrMsg)
	def putListDirect(self, sPath, DataList, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, bResponse=True):
		"""Puts a list of keys. No need to open file first. Returns None."""
		DataNewList = []
		for Tuple in DataList:
			sName, sValue = Tuple
			sName = self._cleanStrFields(sName)
			sValue = self._cleanStrFields(sValue)
			DataNewList.append((sName, sValue))
		self._resetDict()
		self._sMode = 'w'
		self._RequestDict['sOp'] = 'putListDirect'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['iTxn'] = iTxn
		self._RequestDict['DataList'] = DataNewList
		Dict = self._sendDataDb(bResponse=bResponse)
		if bResponse:
			if not Dict['bResult']:
				self.close()
				sErrMsg = ''
				if Dict.has_key('sError'):
					sErrMsg = Dict['sError']
				raise DbmException('putListDirect()', sPath, msg=sErrMsg)
	def search(self, sPath, NameList, iRows, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, *ArgsTuple):
		"""Search for list of duplicate values. It will search for iRows. It does not need open() and close() methods.
		@param sPath: Path
		@param NameList: Search for this list of values
		@param iRows: Number of rows to search for
		@return: ValueList: A list of tuples."""
		NameListNew = []
		for sName in NameList:
			NameListNew.append(self._cleanStrFields(sName))
		self._RequestDict['sOp'] = 'search'
		self._RequestDict['sPath'] = sPath
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['NameList'] = NameListNew
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iTxn'] = iTxn
		self._RequestDict['iRows'] = iRows
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#ValueList = _cleanList(Dict['List'])
			ValueList = Dict['List']
		else:
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('search()', sPath, msg=sErrMsg)
		return ValueList
	def getListDirectMulti(self, EnTableDataList, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, sType=TYPE_LIST):
		"""Doc."""
		self._resetDict()
		self._RequestDict['sOp'] = 'getListDirectMulti'
		self._RequestDict['DataList'] = EnTableDataList
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iTxn'] = iTxn
		Dict = self._sendDataDb()
		if Dict['bResult']:
			EnTableDataList = Dict['List']
			if sType == TYPE_LIST:
				Result = EnTableDataList
			elif sType == TYPE_DICT:
				ResultDict = {}
				for EnTableData in EnTableDataList:
					ResultDict[EnTableData.Path] = EnTableData
				Result = ResultDict
		else:
			self.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('getListDirectMulti()', '', msg=sErrMsg)
		return Result
	def putListDirectMulti(self, EnTableDataList, iDbType=db.DB_BTREE, iFlagsOpen=0, sDbName=None, iFileMode=0660, iTxn=None, bResponse=True):
		"""Doc."""
		self._resetDict()
		self._RequestDict['sOp'] = 'putListDirectMulti'
		self._RequestDict['DataList'] = EnTableDataList
		self._RequestDict['iDbType'] = iDbType
		self._RequestDict['CacheSizeTuple'] = self._CacheSizeTuple
		self._RequestDict['iFlagsOpen'] = iFlagsOpen
		self._RequestDict['iFlagsAdd'] = self._iFlagsAdd
		self._RequestDict['iFileMode'] = iFileMode
		self._RequestDict['sDbName'] = sDbName
		self._RequestDict['iTxn'] = iTxn
		Dict = self._sendDataDb(bResponse=bResponse)
		if bResponse:
			if not Dict['bResult']:
				self.close()
				sErrMsg = ''
				if Dict.has_key('sError'):
					sErrMsg = Dict['sError']
				raise DbmException('putListDirectMulti()', 'Multi Paths', msg=sErrMsg)		

class DbmCursor:
	_RequestDict = {'iDbId': -1}
	_iDbId = -1
	_iCursor = -1
	_iCacheSize = 0
	_sEnvName = ''
	_sTableName = ''
	_bDup = False
	_FlagsTuple = ()
	_sUser = ''
	_sPassword = ''
	_oDbm = None
	_sMode = 'r'
	def __init__(self, oDbm, iDbId, iCursor, sHostName, sTableName, sUser, sPassword, sMode='r'):
		self._iDbId = iDbId
		self._iCursor = iCursor
		self.oDbmConnect = DbmConnect()
		self.oDbmConnect.setDbId(iDbId)
		self.oDbmConnect.setHostName(sHostName)
		self._sTableName = sTableName
		self.oDbmConnect.setUser(sUser)
		self.oDbmConnect.setPassword(sPassword)
		self._oDbm = oDbm
		self._sMode = sMode
		if iDbId:
			self._iDbId = iDbId
			self.oDbmConnect.setDbId(iDbId)
	def _resetDict(self):
		self._RequestDict = {'iDbId': -1}
	def _sendDataDb(self, bResponse=True):
		ResponseDict = self.oDbmConnect.sendDataDb(self._RequestDict, bResponse, sMode=self._sMode)
		return ResponseDict
	def first(self, *ArgsTuple):
		"""Get first data pair. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.first'
		self._RequestDict['ArgsTuple'] = ArgsTuple
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.first()', self._sTableName, msg=sErrMsg)
		return Tuple
	def next(self, *ArgsTuple):
		"""Get next key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.next'
		self._RequestDict['ArgsTuple'] = ArgsTuple
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if Dict['bResult']:
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.next()', self._sTableName, msg=sErrMsg)
		return Tuple
	def nextList(self, iRows, *ArgsTuple):
		"""Get next list of rows. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.nextList'
		self._RequestDict['iRows'] = iRows
		self._RequestDict['ArgsTuple'] = ArgsTuple
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.nextList()', self._sTableName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def firstList(self, iRows, *ArgsTuple):
		"""Get first list of rows. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.firstList'
		self._RequestDict['iRows'] = iRows
		self._RequestDict['ArgsTuple'] = ArgsTuple
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.firstList()', self._sTableName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def firstDupList(self, sName, iRows, *ArgsTuple):
		"""Get first list of rows. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.firstDupList'
		self._RequestDict['iRows'] = iRows
		self._RequestDict['sName'] = sName
		self._RequestDict['ArgsTuple'] = ArgsTuple
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.firstList()', self._sTableName, sName=sName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def prevList(self, iRows, *ArgsTuple):
		"""Get previous list of rows. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.prevList'
		self._RequestDict['iRows'] = iRows
		self._RequestDict['ArgsTuple'] = ArgsTuple
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.prevList()', self._sTableName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def nextDupList(self, iRows, *ArgsTuple):
		"""Get next list of rows duplicates. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.nextDupList'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['iRows'] = iRows
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.nextDupList()', self._sTableName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def nextNoDupList(self, iRows, *ArgsTuple):
		"""Get next list of keys no duplicates. Return TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.nextNoDupList'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['iRows'] = iRows
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.nextNoDupList()', self._sTableName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def prev(self, *ArgsTuple):
		"""Get previous key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.prev'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.prev()', self._sTableName, msg=sErrMsg)
		return Tuple
	def prev_nodup(self, *ArgsTuple):
		"""Get previous no duplicate key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.prev_nodup'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.prev_nodup()', self._sTableName, msg=sErrMsg)
		return Tuple
	def set(self, sName, *ArgsTuple):
		"""Search for key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.set'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['sName'] = sName
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.set()', self._sTableName, sName=sName, msg=sErrMsg)
		return Tuple
	def setList(self, sName, iRows, sMode='dup', *ArgsTuple):
		"""Search for key and return a list. sMode can be 'dup' or 'nodup'. sMode is 'dup' by default [opt]. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.setList'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['sName'] = sName
		self._RequestDict['iRows'] = iRows
		self._RequestDict['sMode'] = sMode
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.setList()', self._sTableName, sName=sName, iRows=iRows, msg=sErrMsg)
		return TupleList
	def next_dup(self, *ArgsTuple):
		"""Next duplicate key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.next_dup'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.next_dup()', self._sTableName, msg=sErrMsg)
		return Tuple
	def getDupList(self, sName):
		"""Get all data associated with a duplicate key. In case no duplicates, returns a list with one entry. Returns TupleList."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.getDupList'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['sName'] = sName
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#TupleList = _cleanList(Dict['List'])
			TupleList = Dict['List']
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.getDupList()', self._sTableName, sName=sName, msg=sErrMsg)
		return TupleList
	def checkDupKey(self, sName, sValue):
		"""Checked duplicate key with sName and sValue. Returns boolean."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.checkDupKey'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['sName'] = sName
		self._RequestDict['sValue'] = sValue
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#bExists = _cleanList(Dict['List'])[0]
			bExists = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.checkDupKey()', self._sTableName, sName=sName, sValue=sValue, msg=sErrMsg)
		return bExists
	def deleteDupKey(self, sName, sValue):
		"""Delete duplicate key with sName and sValue. Returns None."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.deleteDupKey'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['sName'] = sName
		self._RequestDict['sValue'] = sValue
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.deleteDupKey()', self._sTableName, sName=sName, sValue=sValue, msg=sErrMsg)
	def next_nodup(self, *ArgsTuple):
		"""Next no duplicate key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.next_nodup'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.next_nodup()', self._sTableName, msg=sErrMsg)
		return Tuple
	def last(self, *ArgsTuple):
		"""Get last key. Returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.last'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.last()', self._sTableName, msg=sErrMsg)
		return Tuple
	def count(self, *ArgsTuple):
		"""Get number of rows. Returns iCount."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.count'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#iCount = _cleanList(Dict['List'])[0]
			iCount = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.count()', self._sTableName, msg= sErrMsg + '\n' + 'Did you set the cursor?')
		return iCount
	def delete(self, *ArgsTuple):
		"""Delete cursor key. Returns None."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.delete'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.delete()', self._sTableName, msg=sErrMsg)
	def put(self, sName, sValue, *ArgsTuple):
		"""Puts key. Returns None."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.put'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['sName'] = sName
		self._RequestDict['sValue'] = sValue
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.put()', self._sTableName, sName=sName, sValue=sValue, msg=sErrMsg)
	def current(self, *ArgsTuple):
		"""Get current cursor key. returns Tuple."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.current'
		self._RequestDict['iCursor'] = self._iCursor
		self._RequestDict['ArgsTuple'] = ArgsTuple
		Dict = self._sendDataDb()
		if Dict['bResult']:
			#Tuple = _cleanList(Dict['List'])[0]
			Tuple = Dict['List'][0]
		else:
			self.close()
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('cursor.current()', self._sTableName, msg=sErrMsg)
		return Tuple
	def close(self):
		"""Close cursor. Returns None."""
		self._resetDict()
		self._RequestDict['sOp'] = 'cursor.close'
		self._RequestDict['iCursor'] = self._iCursor
		Dict = self._sendDataDb()
		if not Dict['bResult']:
			self._oDbm.close()
			sErrMsg = ''
			if Dict.has_key('sError'):
				sErrMsg = Dict['sError']
			raise DbmException('close()', self._sTableName, msg=sErrMsg)

class DbmCloud(Dbm):
	"""Doc.

	[01 April 2010]
	
	- Similar to SimpleSaas
	- All keys must be integers!!!! If not, throw exception	
	
	No Partitions & Partitions
	==========================
	oDbm = DbmCloud(cloudSchema, env) 
	value = oDbm.getDirect(logicTableName, iKey) => Go to mapping host, get server for sApp and logicTableName. Get table number
	and map to host. If partitions applied for application, get also partition scheme, calculate partition.
	
	value = oDbm.getDirect(logicTable, iKey)
	
	- Mapping sApp and data object name and partition
	- CloudSchema, Schema, Table
	
	sDict = oDbm.getDirect('doc', iResourceNumber)
	
	Sync (Dbm and DbmCloud)
	======================
	conf.py -> relay(days), instant
	
	- Write methods: put, delete must update the sync log.
	- Define host to be synchronize in cloud (schema, table) will have hosts to sync.
	- Define order of schemas to process.
	- Relay triggered by script, which can be included in cron or not. (octopus_repl_now, octopus_repl_relay)
	
	1. Record in a memory spool for 10.000 rows or time delay (1m), whichever comes first, when filled, flush to disk whole data, 
	serialized in json and compressed.
	2. Instant just send with putDirectList() without waiting for response???.
	2.1 Instant -> When filled send to server processing that sends to other servers without waiting response.
	
	"""
	def __init__(self, CloudDict):
		"""Doc."""
		super()
	def _sendDataDb(self, bResponse=True):
		ResponseDict = self.oDbmConnectCloud.sendDataDb(self._RequestDict, bResponse, sMode=self._sMode)
		return ResponseDict
	def _getMachine(self, iName, sApp='', sDomain='', sEnv='', sTable='', sPath='', iParititon=None):
		"""Doc. Maybe going to DbmConnectCloud. sApp?????"""
		sHost = ''
		return sHost
